﻿using System;

namespace Quail
{
    /// <summary>
    /// The TestSession for the current test run
    /// </summary>
    public class TestSession : IDisposable
    {
        private Task _rootTask;
        private bool _disposed;
        private IWebBrowser _browser;

        /// <summary>
        /// Initializes a new instance of the TestSession class
        /// </summary>
        /// <param name="sessionName">Name of test session</param>
        public TestSession(string sessionName)
        {
            SessionName = sessionName;
            DefaultBrowserTimeout = 60000;
        }

        ~TestSession()
        {
            Dispose(false);
        }

        /// <summary>
        /// Gets or sets the root task for this session
        /// </summary>
        public Task RootTask
        {
            get
            {
                return _rootTask;
            }

            set
            {
                _rootTask = value;
            }
        }

        /// <summary>
        /// Gets the ActiveTask for the test session
        /// </summary>
        public Task ActiveTask
        {
            get
            {
                return _rootTask.ActiveTask;
            }
        }

        /// <summary>
        /// Gets the current system time
        /// </summary>
        public DateTime CurrentTime
        {
            get { return DateTime.Now; }
        }

        /// <summary>
        /// Gets or sets a value indicating the default browser timeout (60000)
        /// </summary>
        public int DefaultBrowserTimeout { get; set; }

        /// <summary>
        /// Gets the current browser's Url
        /// </summary>
        public virtual string CurrentUrl
        {
            get
            {
                if (Browser != null)
                    return Browser.Location;

                return null;
            }
        }

        /// <summary>
        /// Gets the name of the current test session
        /// </summary>
        public string SessionName
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets the current WebBrowser for the test session
        /// </summary>
        public IWebBrowser Browser
        {
            get { return _browser; }

            protected set
            {
                var b = _browser;
                _browser = value;
                if (b != null)
                    b.Dispose();
            }
        }

        /// <summary>
        /// Gets or sets the BaseUrl used for relative paths in selenium
        /// </summary>
        public virtual string BaseUrl
        {
            get; set;
        }

        /// <summary>
        /// Gets or sets a value indicating whether to capture network traffic
        /// </summary>
        public virtual bool CaptureNetworkTraffic
        {
            get; set;
        }

        /// <summary>
        /// Begins the logger for the test session
        /// </summary>
        /// <param name="parentTask">The parentTask (null if no parent task)</param>
        public void StartLogger(Task parentTask)
        {
            if (parentTask == null)
            {
                var logger = new TestLogger();
                _rootTask = logger.Start(this);
            }
            else
            {
                _rootTask = Task.BeginTask(parentTask.Logger, this, parentTask, SessionName);
            }
        }

        /// <summary>
        /// Disposes the test shell by stopping it and stopping the logger
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposing && !_disposed)
            {
                _disposed = true;
                Stop();

                if (_rootTask != null)
                {
                    if (_rootTask.IsActive)
                        _rootTask.Finish();
                    _rootTask.Dispose();
                    _rootTask = null;
                }

                var b = Browser as IDisposable;
                if (b != null)
                    b.Dispose();
            }
        }

        /// <summary>
        /// Event args for the OnBeforeStartBrowser event
        /// </summary>
        public class StartBrowserEventArgs : EventArgs
        {
            internal StartBrowserEventArgs(IWebBrowser browser)
            {
                Browser = browser;
            }

            public IWebBrowser Browser { get; private set; }
        }

        /// <summary>
        /// Fired when the StartBrowser method is called, but before the Navigate call
        /// </summary>
        public event EventHandler<StartBrowserEventArgs> OnBeforeStartBrowser;

        /// <summary>
        /// Starts the browser session
        /// </summary>
        /// <param name="url">The url to open</param>
        /// <returns>The new web browser object</returns>
        public virtual IWebBrowser StartBrowser(string url)
        {
            if (Browser == null)
                Browser = CreateBrowser();

            RunOnBeforeStartBrowser();

            Browser.Navigate(url);

            return Browser;
        }

        public void RunOnBeforeStartBrowser()
        {
            if (OnBeforeStartBrowser != null)
                OnBeforeStartBrowser(this, new StartBrowserEventArgs(Browser));
        }

        /// <summary>
        /// Stops the browser and the logger
        /// </summary>
        public virtual void Stop()
        {
        }

        /// <summary>
        /// Creates a new WebBrowser object
        /// </summary>
        /// <returns>A new instance of a WebBrowser object</returns>
        protected virtual IWebBrowser CreateBrowser()
        {
            return new WebBrowser(this);
        }
    }
}
